package com.ibeeking.found.cop.b.rest.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ibeeking.found.common.config.prop.FileOssProp;
import com.ibeeking.found.common.enums.DefaultEnum;
import com.ibeeking.found.common.enums.PublishStatusEnum;
import com.ibeeking.found.common.enums.SyncStatusEnum;
import com.ibeeking.found.common.utils.UrlUtils;
import com.ibeeking.found.common.utils.UserUtils;
import com.ibeeking.found.cop.api.common.dto.OssPolicyDto;
import com.ibeeking.found.cop.api.feign.FileFeignClient;
import com.ibeeking.found.cop.b.rest.service.IKfAccountService;
import com.ibeeking.found.cop.b.rest.service.IMqService;
import com.ibeeking.found.cop.b.rest.service.IWxOpenService;
import com.ibeeking.found.cop.service.common.constants.WxCpMediaFileTypeConstant;
import com.ibeeking.found.cop.service.common.dos.KfAccountDO;
import com.ibeeking.found.cop.service.common.dto.KfAccountDTO;
import com.ibeeking.found.cop.service.common.enums.MqSyncOperatorTypeEnum;
import com.ibeeking.found.cop.service.common.param.KfAccountParam;
import com.ibeeking.found.cop.service.common.param.MqSyncCopParam;
import com.ibeeking.found.cop.service.common.query.KfAccountPageQuery;
import com.ibeeking.found.cop.service.common.query.KfAccountQuery;
import com.ibeeking.found.cop.service.common.vo.KfAccountVO;
import com.ibeeking.found.cop.service.mapper.KfAccountMapper;
import com.ibeeking.found.id.GenerateId;
import com.ibeeking.nematos.core.utils.SpringBeanUtil;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.log.utils.LogUtils;
import com.ibeeking.nematos.utils.bean.BeanUtil;
import com.ibeeking.nematos.utils.data.Collections3;
import com.ibeeking.nematos.utils.file.FileUtils;
import com.ibeeking.nematos.utils.id.IdGenerator;
import com.ibeeking.nematos.utils.json.JsonUtils;
import com.ibeeking.nematos.utils.result.ResponseResult;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpKfService;
import me.chanjar.weixin.cp.api.WxCpMediaService;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpBaseResp;
import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountAdd;
import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountAddResp;
import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountDel;
import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountUpd;
import me.chanjar.weixin.cp.config.impl.WxCpRedissonConfigImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName KfAccountServiceImpl
 * @Description
 * @Author ibeeking
 * @Date 2021-01-27 18:50
 **/
@Service
public class KfAccountServiceImpl extends ServiceImpl<KfAccountMapper, KfAccountDO> implements IKfAccountService {

    @Resource
    private KfAccountMapper kfAccountMapper;

    @Resource
    private IWxOpenService wxOpenServiceImpl;

    @Resource
    private IMqService mqServiceImpl;

    @Resource
    private FileFeignClient fileFeignClient;

    @Resource
    private FileOssProp fileOssProp;

    @Override
    public List<KfAccountVO> list(KfAccountQuery query) {
        List<KfAccountDO> entityDOS = kfAccountMapper.selectList(new LambdaQueryWrapper<KfAccountDO>()
                .eq(query.getId() != null, KfAccountDO::getId, query.getId())
                .like(StringUtils.isNotBlank(query.getName()), KfAccountDO::getName, query.getName())
                .eq(query.getHaveDefault() != null, KfAccountDO::getHaveDefault, query.getHaveDefault())
                .eq(query.getStatus() != null, KfAccountDO::getStatus, query.getStatus())
                .orderByDesc(KfAccountDO::getCreateTime)
        );
        List<KfAccountVO> entityVOS =JsonUtils.jsonToList(entityDOS, KfAccountVO.class);
        entityVOS.forEach(x -> {
            if(StringUtils.isNotEmpty(x.getAvatar())){
                String avartarUrl = UrlUtils.addUrlDomainName(fileOssProp.getHost(), x.getAvatar());
                x.setAvatar(avartarUrl);
            }
            x.setStatusDesc(PublishStatusEnum.getName(x.getStatus()));
            x.setHaveDefaultDesc(DefaultEnum.getDescByValue(x.getHaveDefault()));
            x.setSyncStatusDesc(SyncStatusEnum.getName(x.getSyncStatus()));
        });
        return entityVOS;
    }

    @Override
    public Page<KfAccountVO> pageList(KfAccountPageQuery pageQuery) {
        LambdaQueryWrapper<KfAccountDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(pageQuery.getId() != null, KfAccountDO::getId, pageQuery.getId())
                .like(StringUtils.isNotBlank(pageQuery.getName()), KfAccountDO::getName, pageQuery.getName())
                .eq(pageQuery.getHaveDefault() != null, KfAccountDO::getHaveDefault, pageQuery.getHaveDefault())
                .eq(pageQuery.getStatus() != null, KfAccountDO::getStatus, pageQuery.getStatus())
                .orderByDesc(KfAccountDO::getCreateTime);
        Page<KfAccountDO> entityDOPages = kfAccountMapper.selectPage(new Page<KfAccountDO>(pageQuery.getPageNum(), pageQuery.getPageSize()), wrapper);
        Page<KfAccountVO> entityVOPages = BeanUtil.convertPage(entityDOPages, KfAccountVO.class);
        entityVOPages.getRecords().forEach(f ->{
            if(StringUtils.isNotEmpty(f.getAvatar())){
                String avartarUrl = UrlUtils.addUrlDomainName(fileOssProp.getHost(), f.getAvatar());
                f.setAvatar(avartarUrl);
            }
            f.setStatusDesc(PublishStatusEnum.getName(f.getStatus()));
            f.setHaveDefaultDesc(DefaultEnum.getDescByValue(f.getHaveDefault()));
            f.setSyncStatusDesc(SyncStatusEnum.getName(f.getSyncStatus()));
        });
        return entityVOPages;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean add(KfAccountParam param) {
        checkUnique(param);
        KfAccountDO entityDO = BeanUtil.convertBean(param, KfAccountDO.class);
        if(StringUtils.isNotEmpty(param.getAvatar())){
            String avartarUrl = UrlUtils.removeMallUrlDomainName(fileOssProp.getHost(), param.getAvatar());
            entityDO.setAvatar(avartarUrl);
        }
        entityDO.setId(GenerateId.generateId());
        entityDO.setCreateBy(UserUtils.getUserId());
        entityDO.setCreateTime(LocalDateTime.now());
        entityDO.setModifyTime(LocalDateTime.now());
        entityDO.setHaveDefault(DefaultEnum.NO.getValue());
        entityDO.setSyncStatus(SyncStatusEnum.SYNC_NO.getValue());
        entityDO.setStatus(PublishStatusEnum.DISABLE.getValue());
        return kfAccountMapper.insert(entityDO) > 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean modify(KfAccountParam param) {
        KfAccountDO entityDO = BeanUtil.convertBean(param, KfAccountDO.class);
        if(StringUtils.isNotEmpty(param.getAvatar())){
            String avartarUrl = UrlUtils.removeMallUrlDomainName(fileOssProp.getHost(), param.getAvatar());
            entityDO.setAvatar(avartarUrl);
        }
        entityDO.setModifyBy(UserUtils.getUserId());
        entityDO.setModifyTime(LocalDateTime.now());
        entityDO.setSyncStatus(SyncStatusEnum.SYNC_NO.getValue());
        return kfAccountMapper.updateById(entityDO) > 0;
    }

    @Override
    public KfAccountVO view(Long id) {
        KfAccountDO entityDO = kfAccountMapper.selectById(id);
        if(entityDO == null) throw new BusinessException("没有查到相关记录！");
        KfAccountVO entityVO = BeanUtil.convertBean(entityDO, KfAccountVO.class);
        if(entityVO != null) {
            if(StringUtils.isNotEmpty(entityVO.getAvatar())){
                String avartarUrl = UrlUtils.addUrlDomainName(fileOssProp.getHost(), entityVO.getAvatar());
                entityVO.setAvatar(avartarUrl);
            }
            entityVO.setStatusDesc(PublishStatusEnum.getName(entityDO.getStatus()));
            entityVO.setHaveDefaultDesc(DefaultEnum.getDescByValue(entityDO.getHaveDefault()));
            entityVO.setSyncStatusDesc(SyncStatusEnum.getName(entityDO.getSyncStatus()));
        }
        return entityVO;
    }

    @Override
    public KfAccountDTO queryDefaultKfAccount() {
        KfAccountDO entityDO = kfAccountMapper.selectOne(new LambdaQueryWrapper<KfAccountDO>().eq(KfAccountDO::getHaveDefault, DefaultEnum.YES.getValue()));
        if(entityDO == null)
            entityDO = kfAccountMapper.selectOne(new LambdaQueryWrapper<KfAccountDO>());
        if(entityDO == null) throw new BusinessException("没有查到相关客服账号信息！");
        KfAccountDTO entityDTO = BeanUtil.convertBean(entityDO, KfAccountDTO.class);
        if(entityDTO != null) {
            if(StringUtils.isNotEmpty(entityDTO.getAvatar())){
                String avartarUrl = UrlUtils.addUrlDomainName(fileOssProp.getHost(), entityDTO.getAvatar());
                entityDTO.setAvatar(avartarUrl);
            }
        }
        return entityDTO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean changeStatus(Long id, Integer status) {
        KfAccountDO entityDO = kfAccountMapper.selectById(id);
        if(entityDO == null) throw new BusinessException("没有查到相关记录！");
        entityDO.setStatus(status);
        entityDO.setModifyBy(UserUtils.getUserId());
        entityDO.setModifyTime(LocalDateTime.now());
        return kfAccountMapper.updateById(entityDO) > 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean del(Long id) {
        KfAccountDO entityDO = kfAccountMapper.selectById(id);
        if(entityDO == null) throw new BusinessException("没有查到相关记录！");
        if(entityDO.getSyncStatus() == SyncStatusEnum.SYNC_YES.getValue()) {
            Integer result = this.getBean().syncKfAccountToWxCp(id, true);
            if (result <= 0) throw new BusinessException("同步删除企微的欢迎语失败，请联系管理员！");
        }
        return kfAccountMapper.deleteById(id) > 0;
    }
    /**
     * 从企业微信同步q群信息
     *
     * @param
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer syncKfAccountListFromWxCp(){
        String tenantId = UserUtils.getTenantId();
        MqSyncCopParam mqParam = new MqSyncCopParam();
        mqParam.setTenantId(Long.valueOf(tenantId));
        mqParam.setOperType(MqSyncOperatorTypeEnum.COP_SYNC_KF_ACCOUNT_LIST.getCode());
        mqServiceImpl.sendSyncToWxTaskMessage(mqParam);
        return 1;
    }

    @Override
    public String getKfAccountLinkFromWxCp(Long id){
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer saveOrUpdateOrDeleteBatchKfAccount(Long tenantId, List<KfAccountParam> params){
        if(Collections3.isNotEmpty(params)) {
            List<Long> kfAccountIds = new ArrayList<>();
            List<KfAccountDO> needInsertKfAccountDOS = new ArrayList<>();
            List<KfAccountDO> needUpdateKfAccountDOS = new ArrayList<>();
            List<KfAccountDO> needDeleteKfAccountDOS = new ArrayList<>();
            Map<String, Long> kfAccountOpenKfIdAndIdMap = null;

            List<KfAccountDO> oldKfAccountDOS = kfAccountMapper.selectList(new LambdaQueryWrapper<KfAccountDO>());
            if(Collections3.isNotEmpty(oldKfAccountDOS)) {
                kfAccountOpenKfIdAndIdMap = oldKfAccountDOS.parallelStream().collect(Collectors.toMap(KfAccountDO::getOpenKfid, KfAccountDO::getId, (o, n) -> o));
                List<String> oldOpenKfList = oldKfAccountDOS.parallelStream().map(KfAccountDO::getOpenKfid).collect(Collectors.toList());
                List<String> newOpenKfList = params.parallelStream().map(KfAccountParam::getOpenKfid).collect(Collectors.toList());
                if (Collections3.isNotEmpty(oldOpenKfList) && Collections3.isNotEmpty(newOpenKfList)) {
                    HashSet<String> oldOpenKfHash = new HashSet<>(oldOpenKfList);
                    HashSet<String> newOpenKfHash = new HashSet<>(newOpenKfList);
                    oldOpenKfHash.removeAll(newOpenKfHash);
                    if (oldOpenKfHash.size() > 0) {
                        List<String> needDeleteOpenKfIds = new ArrayList<>(oldOpenKfHash);
                        needDeleteKfAccountDOS = kfAccountMapper.selectList(new LambdaQueryWrapper<KfAccountDO>().in(KfAccountDO::getOpenKfid, needDeleteOpenKfIds));
                    }
                }
            }
            OssPolicyDto ossPolicyDto = getOssFilePolicy();
            for(KfAccountParam accountParam : params){
                Long accountId = 0L;
                KfAccountDO kfAccountDO = BeanUtil.convertBean(accountParam, KfAccountDO.class);
                kfAccountDO.setCreateTime(LocalDateTime.now());
                kfAccountDO.setModifyTime(LocalDateTime.now());
                kfAccountDO.setManagePrivilege(0);
                kfAccountDO.setSyncStatus(SyncStatusEnum.SYNC_YES.getValue());
                kfAccountDO.setStatus(PublishStatusEnum.ENABLE.getValue());
                String avatarUrl = accountParam.getAvatarUrl();
                String openKfId = accountParam.getOpenKfid();
                if(StringUtils.isNotEmpty(avatarUrl)){
                    String avatar = transferFileToOss(openKfId + "_avatar", accountParam.getAvatarUrl(), ossPolicyDto);
                    kfAccountDO.setAvatar(avatar);
                }

                if(kfAccountOpenKfIdAndIdMap != null && kfAccountOpenKfIdAndIdMap.containsKey(openKfId)){
                    needUpdateKfAccountDOS.add(kfAccountDO);
                    accountId = kfAccountOpenKfIdAndIdMap.get(openKfId);
                    kfAccountDO.setId(accountId);
                    kfAccountIds.add(accountId);
                }else{
                    accountId = IdGenerator.getId();
                    kfAccountDO.setId(accountId);
                    needInsertKfAccountDOS.add(kfAccountDO);
                    kfAccountIds.add(accountId);
                }
            }
            if(Collections3.isNotEmpty(needDeleteKfAccountDOS)){
                List<Long> delIds = needDeleteKfAccountDOS.stream().map(KfAccountDO::getId).collect(Collectors.toList());
                kfAccountMapper.deleteBatchIds(delIds);
            }

            if(Collections3.isNotEmpty(needInsertKfAccountDOS)){
                kfAccountMapper.insertBatchSomeColumn(needInsertKfAccountDOS);
            }
            if(Collections3.isNotEmpty(needUpdateKfAccountDOS)){
                super.updateBatchById(needUpdateKfAccountDOS);
            }

        }
        return 1;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer syncKfAccountToWxCp(Long id, Boolean deleted){
        String tenantId = UserUtils.getTenantId();
        KfAccountDO entityDO = kfAccountMapper.selectById(id);
        if(entityDO == null) throw new BusinessException("没有查到相关记录！");
        String openKfid = entityDO.getOpenKfid();

        WxCpService wxCpService = wxOpenServiceImpl.getWxCpService(Long.valueOf(tenantId));
        WxCpRedissonConfigImpl wxCpConfigStorage = (WxCpRedissonConfigImpl)wxCpService.getWxCpConfigStorage();
        if (wxCpConfigStorage == null) {
            throw new BusinessException("获取企微服务失败!");
        }
        wxCpConfigStorage.setCorpSecret("A5pyzWIcAe1wpvKs4R69JVhZeygB1TI8vnbc7g8BU90");
        try {
            String wxCpAccessToken = wxCpService.getAccessToken(true);
            wxCpConfigStorage.updateAccessToken(wxCpAccessToken, 7200);
            wxCpService.setWxCpConfigStorage(wxCpConfigStorage);
        }catch(Exception ex){}
        String corpId = wxCpConfigStorage.getCorpId();
        Integer agentId = wxCpConfigStorage.getAgentId();

        WxCpKfService wxCpKfService = wxCpService.getKfService();
        if (wxCpKfService == null) throw new BusinessException("获取客服服务出错!");

        if(deleted){
            try {
                if(agentId == null) return 0;
                if (StringUtils.isEmpty(openKfid)) return 0;
                WxCpKfAccountDel WxCpKfAccountDel = new WxCpKfAccountDel();
                WxCpKfAccountDel.setOpenKfid(openKfid);
                WxCpBaseResp wxCpBaseResp = wxCpKfService.delAccount(WxCpKfAccountDel);
                if (!wxCpBaseResp.success()) {
                    return 0;
                }
            } catch (WxErrorException ex) {
                return 0;
            }
        }else {
            String kfAvatar = entityDO.getAvatar();
            if(StringUtils.isNotEmpty(kfAvatar)){
                try {
                    String kfAvatarUrl = UrlUtils.addUrlDomainName(fileOssProp.getHost(), kfAvatar);
                    String kfAvatarFileName = FileUtils.getUrlFileName(kfAvatar);
                    WxCpMediaService wxCpMediaService = wxCpService.getMediaService();
                    if (wxCpMediaService == null) throw new BusinessException("获取媒体自研服务出错!");
                    WxMediaUploadResult WxMediaUploadResult = wxCpMediaService.upload(WxCpMediaFileTypeConstant.WXCP_MEDIA_FILE_TYPE_IMAGE, kfAvatarFileName, kfAvatarUrl);
                    if(WxMediaUploadResult != null){
                        entityDO.setAvatarMediaId(WxMediaUploadResult.getMediaId());
                        entityDO.setAvatarUrl(WxMediaUploadResult.getUrl());
                    }
                }catch(Exception ex){
                    throw new BusinessException("上传客服的头像出错" + ex);
                }
            }
            if (StringUtils.isEmpty(openKfid)) {
                try {
                    WxCpKfAccountAdd wxCpKfAccountAdd = new WxCpKfAccountAdd();
                    wxCpKfAccountAdd.setName(entityDO.getName());
                    if(StringUtils.isNotEmpty(entityDO.getAvatarMediaId())) {
                        wxCpKfAccountAdd.setMediaId(entityDO.getAvatarMediaId());
                    }
                    WxCpKfAccountAddResp wxCpKfAccountAddResp = wxCpKfService.addAccount(wxCpKfAccountAdd);
                    if (wxCpKfAccountAddResp != null) {
                        String rtnOpenKfid = wxCpKfAccountAddResp.getOpenKfid();
                        entityDO.setOpenKfid(rtnOpenKfid);
                        entityDO.setSyncStatus(SyncStatusEnum.SYNC_YES.getValue());
                    } else {
                        entityDO.setOpenKfid(null);
                        entityDO.setSyncStatus(SyncStatusEnum.SYNC_NO.getValue());
                    }
                } catch (WxErrorException ex) {
                    LogUtils.error("同步客服账号出错" + ex);
                    entityDO.setOpenKfid(null);
                    entityDO.setSyncStatus(SyncStatusEnum.SYNC_NO.getValue());
                }
            } else {
                try {
                    WxCpKfAccountUpd wxCpKfAccountUpd = new WxCpKfAccountUpd();
                    wxCpKfAccountUpd.setOpenKfid(openKfid);
                    wxCpKfAccountUpd.setName(entityDO.getName());
                    if(StringUtils.isNotEmpty(entityDO.getAvatarMediaId())) {
                        wxCpKfAccountUpd.setMediaId(entityDO.getAvatarMediaId());
                    }
                    WxCpBaseResp wxCpBaseResp = wxCpKfService.updAccount(wxCpKfAccountUpd);
                    if (wxCpBaseResp.success()) {
                        entityDO.setSyncStatus(SyncStatusEnum.SYNC_YES.getValue());
                    } else {
                        entityDO.setSyncStatus(SyncStatusEnum.SYNC_NO.getValue());
                    }
                } catch (WxErrorException ex) {
                    LogUtils.error("同步客服账号出错" + ex);
                    entityDO.setSyncStatus(SyncStatusEnum.SYNC_NO.getValue());
                }
            }
            if (entityDO != null) {
                kfAccountMapper.updateById(entityDO);
            }
        }
        return 1;
    }
    /**
     * 校验唯一性
     *
     * @param param
     */
    public void checkUnique(KfAccountParam param) {
        if (param == null) {
            throw new BusinessException("当前记录不存在!");
        }
        //code name确保等级唯一性
        LambdaQueryWrapper<KfAccountDO> queryWrapper = new LambdaQueryWrapper<KfAccountDO>()
                .ne(param.getId() != null, KfAccountDO::getId, param.getId())
                .eq(KfAccountDO::getName, param.getName());
        List<KfAccountDO> dos = kfAccountMapper.selectList(queryWrapper);
        if (Collections3.isNotEmpty(dos)) {
            throw new BusinessException("已经存在同名的记录!");
        }
    }

    private String transferFileToOss(String id, String fileUrl, OssPolicyDto policy){
        try {
            String fileName = (String.valueOf(System.currentTimeMillis())).concat("_".concat(id).concat(".png"));
            String fileTag = policy.getDir() + fileName;
            MultipartFile multipartFile = FileUtils.getMultipartFile(fileUrl, fileName, fileTag);
            ResponseResult<String> responseResult = fileFeignClient.uploadFile(multipartFile);
            String fileUploadPath = responseResult.getData();
            return UrlUtils.removeUrlDomainName(fileUploadPath);
        } catch (Exception ex) {
            throw new BusinessException("上传头像文件失败：" + ex.toString());
        }
    }

    private OssPolicyDto getOssFilePolicy(){
        ResponseResult<OssPolicyDto> responseResult = fileFeignClient.policy();
        return responseResult.getData();
    }

    private IKfAccountService getBean(){
        return SpringBeanUtil.getBean(KfAccountServiceImpl.class);
    }
}
